//go:build windows
// +build windows

// 包 systray 是一个跨平台的 Go 库，用于在通知区域放置一个图标和菜单。
package 托盘类

import (
	"fmt"
	"log"
	"runtime"
	"sync"
	"sync/atomic"
)

var (
	systrayReady  func()
	systrayExit   func()
	menuItems     = make(map[uint32]*X结构_菜单项)
	menuItemsLock sync.RWMutex

	currentID             = uint32(0)
	quitOnce              sync.Once
	dClickTimeMinInterval int64 = 500
)

func init() {
	runtime.LockOSThread()
}

type X接口_菜单项 interface {
	X显示菜单() error
}

// X结构_菜单项 用于跟踪系统托盘中的每个菜单项。
// 不要直接创建它，而是使用 systray.AddMenuItem() 返回的实例。
type X结构_菜单项 struct {
	// ClickedCh 是在菜单项被点击时将收到通知的通道
	click func()

	// id 唯一标识一个菜单项，不建议修改。
	id uint32
	// title 是菜单项上显示的文本
	title string
	// tooltip 是指向菜单项时显示的文本
	tooltip string
	// 快捷键 菜单快捷键
	shortcutKey string
	// 禁用的菜单项会显示为灰色，并且在点击时不会产生任何效果。
	disabled bool
	// 勾选的菜单项在标题前有一个对勾符号
	checked bool
	// 该菜单项是否有复选框（Linux）
	isCheckable bool
	// 父级项目，用于子菜单
	parent *X结构_菜单项
}

func (item *X结构_菜单项) X鼠标单击(回调函数 func()) {
	item.click = 回调函数
}

func (item *X结构_菜单项) X取文本() string {
	if item.parent == nil {
		return fmt.Sprintf("菜单项[%d, %q]", item.id, item.title)
	}
	return fmt.Sprintf("菜单项[%d, 父菜单项 %d, %q]", item.id, item.parent.id, item.title)
}

// newMenuItem 返回一个已填充的 MenuItem 对象
func newMenuItem(title string, tooltip string, parent *X结构_菜单项) *X结构_菜单项 {
	return &X结构_菜单项{
		id:          atomic.AddUint32(&currentID, 1),
		title:       title,
		tooltip:     tooltip,
		shortcutKey: "",
		disabled:    false,
		checked:     false,
		isCheckable: false,
		parent:      parent,
	}
}

// X阻塞运行 初始化 GUI 并启动事件循环，然后调用 onReady 回调函数。它会阻塞直到调用 systray.Quit()。
func X阻塞运行(执行函数, 退出回调 func()) {
	setInternalLoop(true)
	注册函数(执行函数, 退出回调)

	nativeLoop()
}

// 设置鼠标左键双击事件的时间间隔 默认500毫秒
func X设置双击最小间隔(毫秒 int64) {
	dClickTimeMinInterval = 毫秒
}

// 设置托盘鼠标左键点击事件
func X事件_左键点击(回调函数 func(菜单 X接口_菜单项)) {
	setOnClick(回调函数)
}

// 设置托盘鼠标左键双击事件
func X事件_左键双击(回调函数 func(菜单 X接口_菜单项)) {
	setOnDClick(回调函数)
}

// 设置托盘鼠标右键事件反馈回调
// 支持windows 和 macosx，不支持linux
// 设置事件，菜单默认将不展示，通过menu.ShowMenu()函数显示
// 未设置事件，默认右键显示托盘菜单
// macosx ShowMenu()只支持OnRClick函数内调用
func X事件_右键单击(回调函数 func(菜单 X接口_菜单项)) {
	setOnRClick(回调函数)
}

// X异步运行 允许 systemtray 模块与其他工具包一起使用。
// 返回的启动和结束函数应在应用程序启动时和即将结束时由工具包调用。
func X异步运行(就绪回调, 退出回调 func()) (开始, 结束 func()) {
	注册函数(就绪回调, 退出回调)

	return nativeStart, func() {
		nativeEnd()
		X退出()
	}
}

// 注册函数 初始化GUI并注册回调，但依赖调用者在其他地方运行事件循环。如果程序需要显示其他UI元素（例如，webview），这很有用。
// 为了克服某些操作系统的问题，在Catalina之前的macOS版本中，调用此函数与调用Run()完全相同。
func 注册函数(执行函数 func(), 退出回调 func()) {
	if 执行函数 == nil {
		systrayReady = nil
	} else {
		var readyCh = make(chan interface{})
		// 在单独的 goroutine 中运行 onReady，以避免阻塞事件循环
		go func() {
			<-readyCh
			执行函数()
		}()
		systrayReady = func() {
			systrayReady = nil
			close(readyCh)
		}
	}
	// 与 onReady 不同，onExit 在事件循环中运行，以确保在进程终止之前它有足够的时间完成。
	if 退出回调 == nil {
		退出回调 = func() {}
	}
	systrayExit = 退出回调
	registerSystray()
}

// X删除所有菜单项 将移除所有菜单项
func X删除所有菜单项() {
	resetMenu()
}

// X退出 the systray
func X退出() {
	quitOnce.Do(quit)
}

// X加入菜单项 添加一个具有指定标题和提示信息的菜单项。
// 该方法可以从不同的 goroutine 安全地调用。
// 在 Windows 和 OSX 上，默认情况下创建的菜单项是可选中的。对于 Linux，您需要使用 AddMenuItemCheckbox。
func X加入菜单项(名称 string) *X结构_菜单项 {
	item := newMenuItem(名称, "", nil)
	item.update()
	return item
}

// X加入分隔栏 在菜单中添加一个分隔栏。
func X加入分隔栏() {
	addSeparator(atomic.AddUint32(&currentID, 1))
}

// X加入子菜单项 添加一个带有指定标题和工具提示的嵌套子菜单项。
// 该方法可以从不同的 goroutine 安全地调用。
// 在 Windows 和 OSX 上，默认情况下创建的菜单项是可以勾选的。对于 Linux，您需要使用 AddSubMenuItemCheckbox。
func (item *X结构_菜单项) X加入子菜单项(名称 string) *X结构_菜单项 {
	child := newMenuItem(名称, "", item)
	child.update()
	return child
}

// X设置名称 设置要在菜单项上显示的文本
func (item *X结构_菜单项) X设置名称(标题 string) {
	item.title = 标题
	item.update()
}

// X设置提示 设置鼠标悬停时显示的提示信息
// 这段注释的意思是，`X设置提示` 函数用于设置当鼠标悬停在某个元素上时显示的提示信息（tooltip）。
func (item *X结构_菜单项) X设置提示(提示 string) {
	item.tooltip = 提示
	item.update()
}

// X是否禁用 检查菜单项是否被禁用
func (item *X结构_菜单项) X是否禁用() bool {
	return item.disabled
}

// 无论菜单项之前是否已启用，都启用它。
func (item *X结构_菜单项) X启用菜单项() {
	item.disabled = false
	item.update()
}

// 无论菜单项之前是否已禁用，都将其禁用
func (item *X结构_菜单项) X禁用菜单项() {
	item.disabled = true
	item.update()
}

// X隐藏菜单项 隐藏菜单项
func (item *X结构_菜单项) X隐藏菜单项() {
	hideMenuItem(item)
}

// X显示菜单项 显示一个之前隐藏的菜单项
func (item *X结构_菜单项) X显示菜单项() {
	showMenuItem(item)
}

// X是否选中 返回菜单项是否带有选中标记
func (item *X结构_菜单项) X是否选中() bool {
	return item.checked
}

// 无论菜单项之前是否已选中，都检查该菜单项
func (item *X结构_菜单项) X选中菜单项() {
	item.checked = true
	item.update()
}

// 无论菜单项之前是否已取消选中，都取消选中该菜单项。
func (item *X结构_菜单项) X取消选中() {
	item.checked = false
	item.update()
}

// 更新将菜单项的变化传播到系统托盘
func (item *X结构_菜单项) update() {
	menuItemsLock.Lock()
	menuItems[item.id] = item
	menuItemsLock.Unlock()
	addOrUpdateMenuItem(item)
}

func systrayMenuItemSelected(id uint32) {
	menuItemsLock.RLock()
	item, ok := menuItems[id]
	menuItemsLock.RUnlock()
	if !ok {
		log.Printf("systray错误：没有带ID的菜单项 %d\n", id)
		return
	}
	if item.click != nil {
		item.click()
	}
}
